﻿// -----------------------------------------------------------------------
// <copyright file="Direction.cs" company="The BomberJoe Team">
// Author: Oliver Phillip Roer      
//          <olpr@itu.dk>
//         Søren Lillethorup Vange
//          <slil@itu.dk>
// </copyright>
// -----------------------------------------------------------------------
namespace BomberGame
{
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;

    /// <summary>
    /// A class which should be perceived as an axis.
    /// </summary>
    public enum Axis
    {
        X, Y
    }

    /// <summary>
    /// A class describing a compass direction which can only be North, South, East or West,
    /// along with several helper methods.
    /// </summary>
    public class Direction
    {
        public static readonly Direction North = new Direction(new IntVector(0, -1), Axis.Y);
        public static readonly Direction East = new Direction(new IntVector(1, 0), Axis.X);
        public static readonly Direction South = new Direction(new IntVector(0, 1), Axis.Y);
        public static readonly Direction West = new Direction(new IntVector(-1, 0), Axis.X);

        /// <summary>
        /// The vector representation of the direction.
        /// </summary>
        public readonly IntVector Vector;

        /// <summary>
        /// The axis which the Direction aligns to.
        /// </summary>
        public readonly Axis Axis;

        /// <summary>
        /// Initializes a new instance of the <see cref="Direction"/> class.
        /// </summary>
        /// <param name="gridVector">
        /// The grid vector.
        /// </param>
        /// <param name="axis">
        /// The axis.
        /// </param>
        private Direction(IntVector gridVector, Axis axis)
        {
            Vector = gridVector;
            Axis = axis;
        }

        /// <summary>
        /// Gets an enumerable that enumerates over the directions
        /// </summary>
        /// <returns>
        /// The enumerable
        /// </returns>
        [Pure]
        public static IEnumerable<Direction> GetEnumerable()
        {
            yield return North;
            yield return East;
            yield return South;
            yield return West;
        }

        /// <summary>
        /// Returns the opposite direction of the given direction.
        /// </summary>
        /// <param name="direction">The direction of which we wish to get the opposite.</param>
        /// <returns>The opposite direction.</returns>
        [Pure]
        public static Direction Opposite(Direction direction)
        {
            Contract.Requires(direction != null);
            Contract.Ensures(Contract.Result<Direction>() != null);            
            Contract.Ensures(direction != Contract.Result<Direction>());
            // ReSharper disable PossibleNullReferenceException
            Contract.Ensures(direction.Axis == Contract.Result<Direction>().Axis);
            // ReSharper restore PossibleNullReferenceException
            return (direction.Axis == Axis.X) ? (direction == East ? West : East) : (direction == North ? South : North);
        }

        /// <summary>
        /// Converts the direction into an integer (1) with a sign that matches the direction's position on its axis.
        /// E.g. North and West converts to -1, South and East converts to 1.
        /// </summary>
        /// <returns>
        /// A signed integer (1 or -1).
        /// </returns>
        [Pure]
        public int GetAxisSign()
        {
            Contract.Ensures(Contract.Result<int>() == 1 | Contract.Result<int>() == -1);
            return Axis == Axis.X ? Vector.X : Vector.Y;
        }
    }
}
